package com.cskaoyan.javase._2inner._6lambda._1basic;

/**
 * 对于Lambda表达式的语法:
 *      (抽象方法的形参列表) -> {
 *          // 抽象方法重写的方法体
 *       }
 * 如何简化呢?
 * Lambda表达式能够简化的前提是：
 *      它是功能接口的子类对象，而功能接口中有且只有一个必须要实现的抽象方法！
 *      也就是说Lambda表达式实现的抽象方法是固定的
 *
 * 具体来说:
 *      1."()"能不能简化?
 *      ()中装的是抽象方法的形参列表
 *          形参列表中的数据类型,写与不写都不会影响,所以干脆不要写
 *          特殊的,当形参列表就只有一个参数时,干脆连"()"都可以省略
 *          但是注意,方法如果是无参的,是不能省略"()"的
 *
 *      2."{}"能不能简化?
 *          当Lambda表达式的方法实现,仅有一条语句时,那么可以省略"{}"
 *          特殊的,当该一条语句,就是重写方法的返回值语句,那么连"return"可以一起省略,直接写返回值
 *
 * 实际开发中,Lambda表达式的使用最需要被简化,被去掉,就是"{}"
 *      但是不太可能一句话就能把方法写完
 *      所以Lambda表达式的"{}"就不能直接省略了
 *      这样的话, 不够简洁,不够优雅
 * 所以Java推出了"方法引用"来解决这个问题.
 *
 * 方法引用的语法:
 *  指的是Lambda表达式当中抽象方法的实现,不再手动写在Lambda表达式当中
 *  而是找到一个已经存在的方法,用已经实现的方法,作为Lambda表达式当中抽象方法的实现
 *
 *  什么样的方法,可以作为Lambda表达式当中抽象方法的实现呢?
 *  对于抽象方法 "返回值类型 方法名(形参列表);"
 *  要求它的实现方法:
 *      1.访问权限修饰符没有直接影响,但是在使用Lambda表达式的位置,必须能够访问该方法
 *      2.static有无,没有直接影响,无非是方法的调用方式不同.
 *      3.返回值类型要保持和抽象方法中的返回值类型"兼容":
 *      如果是基本数据类型和void,必须完全保持一致
 *      如果是父类类型,那么可以允许重写方法是子类类型
 *
 *      4.方法名没有影响,无所谓.一样可以,不一样也可以.
 *      5.形参列表必须保持完全一致
 *
 * 方法引用的具体语法:
 * 语法一:
 *      (形参列表) -> 已实现方法的方法调用(形参列表);
 *      解释:
 *      1.语法上左右两边都是形参列表,必须保持一致
 *      2.已实现方法的方法调用,就是在写Lambda表达式的位置,调用已实现方法
 *      static方法直接类名点调用
 *      成员方法对象名点调用
 *
 * 语法二(更常用):
 *     去掉"->" 去掉Lambda表达式运算符
 *     功能接口名 引用 = 方法的归属者::方法名;
 *     解释:
 *          1.何为方法的归属者?
 *              static方法属于类,写类名
 *              成员方法属于对象,写匿名对象或者对象名
 *          2."::"是两个冒号组成的
 *          3.整个语法中,没有小括号.
 *
 * @since 11:38
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        INoReturnTwoParam ip1 = (int a, int b) -> {
            System.out.println(a + b);
        };
        ip1.test(1, 1);
        // 上述Lambda表达式简化:
        INoReturnTwoParam ip2 = (a, b) -> {
            System.out.println(a + b);
        };
        ip2.test(10, 10);

        INoReturnOneParam ip3 = a -> {
            System.out.println("你是一个好人!" + a);
        };
        ip3.test(666);
        // 上述Lambda表达式简化
        INoReturnOneParam ip4 = a -> System.out.println("你是一个好人!" + a);
        ip4.test(777);

        IHasReturnNoParam ip5 = () -> {
            return 0;
        };
        // 上述Lambda表达式简化
        IHasReturnNoParam ip6 = () -> 0;
        System.out.println(ip6.test());

        System.out.println("--------------------");
        // 以下是方法引用的Lambda表达式实现
        INoReturnNoParam ip7 = () -> myTest();
        ip7.test();
        System.out.println("--------------------");

        IHasReturnTwoParam ip8 = (a, b) -> new Demo().test(a, b);
        System.out.println(ip8.test(100, 200));

        System.out.println("-----------------------");
        INoReturnNoParam ip9 = Demo::myTest;
        ip9.test();
        System.out.println("------------------");
        IHasReturnTwoParam ip10 = new Demo()::test;
        System.out.println(ip10.test(200, 300));

    }

    private static void myTest() {
        System.out.println("hello world!");
        System.out.println("你好世界!");
        System.out.println("扣你七娃!");
    }

    public int test(int num1, int num2) {
        System.out.println("这两个数的和是" + (num1 + num2));
        System.out.println("西瓜真好吃!");
        return 666;
    }
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}